package com.swinboo.im.service.impl;

import com.easemob.im.server.EMException;
import com.easemob.im.server.EMService;
import com.huang.entity.result.HStringResult;
import com.huang.entity.result.ResultBuilder;
import com.huang.utils.ObjectIdUtils;
import com.mongodb.BasicDBObject;
import com.swinboo.im.constant.ChatRecordConstants;
import com.swinboo.im.converter.ChatRecord2ChatRecordInfo;
import com.swinboo.im.converter.SendSingleMsgParam2EMMsgBody;
import com.swinboo.im.entity.info.ChatRecordInfo;
import com.swinboo.im.entity.param.GetChatRecordParam;
import com.swinboo.im.entity.param.SendSingleMsgParam;
import com.swinboo.im.entity.repository.ChatRecord;
import com.swinboo.im.entity.to.EMMsgBody;
import com.swinboo.im.service.EMMsgService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

import static java.util.Optional.ofNullable;

/**
 * @author Swinboo
 * @date 2022-03-16 20:54
 * @description:
 */

@Service
@Slf4j
public class EMMsgServiceImpl implements EMMsgService {

    @Resource
    private EMService emService;
    @Resource
    private SendSingleMsgParam2EMMsgBody sendSingleMsgParam2EMMsgBody;
    @Resource
    private MongoTemplate mongoTemplate;
    @Resource
    private ChatRecord2ChatRecordInfo chatRecord2ChatRecordInfo;

    @Override
    public HStringResult<Boolean> send(SendSingleMsgParam sendSingleMsgParam) {
        EMMsgBody emMsgBody = sendSingleMsgParam2EMMsgBody.doConvert(sendSingleMsgParam);
        try {
            emService.message().send()
                    .fromUser(emMsgBody.getFrom())
                    .toUser(emMsgBody.getTo())
                    .text(msg -> msg.text(emMsgBody.getMsgBody()))
                    .send()
                    .block();
            log.info("消息发送成功");
            ChatRecord savedRecord = saveRecord(sendSingleMsgParam);
            if (ofNullable(savedRecord).isPresent()) {
                log.info("消息保存成功： " + savedRecord.toString());
                return ResultBuilder.successHSingle(true);
            } else {
                return ResultBuilder.successHSingleMsg("消息发送成功但消息保存失败");
            }
        } catch (EMException e) {
            log.info("消息发送失败", e.getMessage());
            return ResultBuilder.failHSingle("消息发送失败");
        }
    }

    @Override
    public HStringResult<ChatRecordInfo> getRecord(GetChatRecordParam getChatRecordParam) {
        ChatRecord chatRecord = null;
        try {
            String id = generateRecordId(getChatRecordParam.getU1(),
                    getChatRecordParam.getU2());
            chatRecord = mongoTemplate.findById(id, ChatRecord.class, ChatRecord.DOCUMENT_NAME);
            ChatRecordInfo chatRecordInfo = chatRecord2ChatRecordInfo.doConvert(chatRecord);
            return ResultBuilder.successHSingle(chatRecordInfo);
        } catch (Exception e) {
            return ResultBuilder.failHSingle("聊天记录获取失败: " + e.getMessage());
        }
    }

    private ChatRecord saveRecord(SendSingleMsgParam sendSingleMsgParam) {
        ChatRecord chatRecord = new ChatRecord();
        buildRecord(sendSingleMsgParam, chatRecord);
        chatRecord.setLastTime(new Date());

        BasicDBObject dbObject = new BasicDBObject();
        dbObject.put(ChatRecordConstants.ID, chatRecord.getId());
        //指定返回的字段
        BasicDBObject fieldsObject = new BasicDBObject();
        fieldsObject.put(ChatRecordConstants.ID, true);
        Query basicQuery = new BasicQuery(dbObject.toJson(), fieldsObject.toJson());
        ChatRecord res = mongoTemplate.findOne(basicQuery, ChatRecord.class, ChatRecord.DOCUMENT_NAME);
        if (!ofNullable(res).isPresent()) {
            mongoTemplate.save(chatRecord, ChatRecord.DOCUMENT_NAME);
        } else {
            //1.更新条件
            Query query = Query.query(Criteria.where(ChatRecordConstants.ID).is(chatRecord.getId()));
            //2.更新内容
            Update update = new Update();
            update.set(ChatRecordConstants.LAST_TIME, new Date());
            //单条更新
            mongoTemplate.updateFirst(query, update, ChatRecord.class);
        }

        ChatRecord.RecordItem recordItem = new ChatRecord.RecordItem();
        ChatRecord.RecordItem.MsgBody msgBody = new ChatRecord.RecordItem.MsgBody();

        recordItem.setId(ObjectIdUtils.getInstance().nextId() + "");
        recordItem.setMsgBody(msgBody);
        recordItem.setFrom(sendSingleMsgParam.getFromUId());
        recordItem.setTo(sendSingleMsgParam.getToUId());
        recordItem.setSendTime(new Date());
        recordItem.setU1Deleted(Boolean.FALSE);
        recordItem.setU2Deleted(Boolean.FALSE);

        msgBody.setMsgType(sendSingleMsgParam.getType());
        msgBody.setMsgContent(sendSingleMsgParam.getContent());


        Query query = Query.query(new Criteria().andOperator(Criteria.where(ChatRecordConstants.ID).is(chatRecord.getId())));
        Update updateInc = new Update();
        Update updateSet = new Update();

        mongoTemplate.upsert(query, updateInc.inc(ChatRecordConstants.COUNT, 1), ChatRecord.class);
        mongoTemplate.upsert(query, updateSet.addToSet(ChatRecord.RECORD_LIST, recordItem), ChatRecord.class);
        return chatRecord;
    }

    public String generateRecordId(String u1, String u2) {
        Long l1 = Long.parseLong(StringUtils.substring(u1, 1));
        Long l2 = Long.parseLong(StringUtils.substring(u2, 1));
        return l1 < l2 ? l1 + "-" + l2 : l2 + "-" + l1;
    }

    public void buildRecord(SendSingleMsgParam sendSingleMsgParam, ChatRecord chatRecord) {
        String id = generateRecordId(sendSingleMsgParam.getFromUId(), sendSingleMsgParam.getToUId());
        Long from = Long.parseLong(StringUtils.substring(sendSingleMsgParam.getFromUId(), 1));
        Long to = Long.parseLong(StringUtils.substring(sendSingleMsgParam.getToUId(), 1));
        if (from < to) {
            chatRecord.setU1(sendSingleMsgParam.getFromUId());
            chatRecord.setU2(sendSingleMsgParam.getToUId());
        } else {
            chatRecord.setU1(sendSingleMsgParam.getToUId());
            chatRecord.setU2(sendSingleMsgParam.getFromUId());
        }
        chatRecord.setId(id);
    }
}
